from rest_framework.test import APITestCase
from rest_framework import status
from django.contrib.auth import get_user_model

from apps.devices.models import Device
from apps.devices.serializers import DeviceSerializer
from apps.rooms.models import Room

User = get_user_model()


class DeviceTestCase(APITestCase):
    def setUp(self):
        Device.objects.all().delete()
        Room.objects.all().delete()

        # 创建两个房间
        self.room1 = Room.objects.create(name="Room 1")
        self.room2 = Room.objects.create(name="Room 2")

        # 创建两个设备
        self.device1 = Device.objects.create(
            device_name="Test Device 1",
            device_type="Sensor",
            room=self.room1,
            status="online",
            control_value=0
        )
        self.device2 = Device.objects.create(
            device_name="Test Device 2",
            device_type="Actuator",
            room=self.room2,
            status="offline",
            control_value=0
        )

    def test_device_list_get_all(self):
        response = self.client.get('/devices/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        devices = Device.objects.all()
        serializer = DeviceSerializer(devices, many=True)
        self.assertEqual(response.data, serializer.data)
        self.assertEqual(len(response.data), 2)

    def test_device_list_get_by_location(self):
        response = self.client.get(f'/devices/?room_name={self.room1.name}')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        devices = Device.objects.filter(room__name="Room 1")
        serializer = DeviceSerializer(devices, many=True)
        self.assertEqual(response.data, serializer.data)
        self.assertEqual(len(response.data), 1)
        self.assertEqual(response.data[0]['device_id'], self.device1.device_id)

    def test_device_list_post_valid(self):
        room3 = Room.objects.create(name="Room 3")
        data = {
            "device_name": "New Device From Test",
            "device_type": "Controller",
            "room": room3.room_id,
            "status": "online"
        }
        response = self.client.post('/devices/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data, {"message": "Device created"})

        new_device = Device.objects.filter(device_name="New Device From Test")
        self.assertTrue(new_device.exists())

    def test_device_list_post_invalid_missing_required_field(self):
        room3 = Room.objects.create(name="Room 3")
        data = {
            "device_type": "Controller",
            "room": room3.room_id,
            "status": "online"
        }
        response = self.client.post('/devices/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn("device_name", response.data["message"])

    def test_device_list_post_with_provided_device_id_is_ignored(self):
        kitchen = Room.objects.create(name="Kitchen")
        data = {
            "device_id": 99999,
            "device_name": "Device with custom ID attempt",
            "device_type": "Sensor",
            "room": kitchen.room_id,
            "status": "online"
        }
        response = self.client.post('/devices/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        created_device = Device.objects.get(device_name="Device with custom ID attempt")
        self.assertNotEqual(created_device.device_id, 99999)
        self.assertIsInstance(created_device.device_id, int)

    def test_device_detail_get_valid(self):
        response = self.client.get(f'/devices/{self.device1.device_id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        device = Device.objects.get(device_id=self.device1.device_id)
        serializer = DeviceSerializer(device)
        self.assertEqual(response.data, serializer.data)

    def test_device_detail_get_invalid(self):
        response = self.client.get('/devices/999999/')
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
        self.assertIn("detail", response.data)

    def test_device_detail_put_valid(self):
        room1a = Room.objects.create(name="Room 1A")
        data = {
            "device_name": "Updated Device 1",
            "room": room1a.room_id
        }
        response = self.client.put(f'/devices/{self.device1.device_id}/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data, {"message": "updated"})

        device = Device.objects.get(device_id=self.device1.device_id)
        self.assertEqual(device.device_name, "Updated Device 1")
        self.assertEqual(device.room.name, "Room 1A")

    def test_device_detail_put_invalid_id(self):
        room1a = Room.objects.create(name="Room 1A")
        data = {
            "device_name": "Updated Device 1",
            "room": room1a.room_id
        }
        response = self.client.put('/devices/999999/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
        self.assertIn("detail", response.data)

    def test_device_detail_delete_valid(self):
        response = self.client.delete(f'/devices/{self.device1.device_id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data, {"message": "deleted"})
        self.assertFalse(Device.objects.filter(device_id=self.device1.device_id).exists())

    def test_device_detail_delete_invalid(self):
        response = self.client.delete('/devices/999999/')
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
        self.assertIn("detail", response.data)

    def test_device_control_post_valid(self):
        data = {
            "action": "turn_on",
            "value": 1
        }
        response = self.client.post(f'/devices/{self.device1.device_id}/control/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data["message"], "ok")
        self.assertEqual(response.data["device_id"], self.device1.device_id)
        self.assertEqual(response.data["control_value"], 1)

        updated_device = Device.objects.get(device_id=self.device1.device_id)
        self.assertEqual(updated_device.control_value, 1)

    def test_device_control_post_invalid_missing_value(self):
        data = {
            "action": "turn_on"
        }
        response = self.client.post(f'/devices/{self.device1.device_id}/control/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn("value", response.data["message"])

    def test_device_control_post_invalid_value_type(self):
        data = {
            "action": "set_temp",
            "value": "invalid_number"
        }
        response = self.client.post(f'/devices/{self.device1.device_id}/control/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn("value", response.data["message"])

    def test_device_control_post_invalid_device_id(self):
        data = {
            "action": "turn_on",
            "value": 1
        }
        response = self.client.post('/devices/999999/control/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
        self.assertIn("detail", response.data)
